package lol.clann.bukkit.pluginboot.util;

import lol.clann.clannboot.annotation.inject.Inject;
import lol.clann.clannboot.annotation.svc.PostInstance;
import lol.clann.clannboot.annotation.svc.Service;
import lol.clann.clannboot.util.clazz.*;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;

/**
 * @author pyz
 * @date 2018/8/5 上午9:04
 */
@Service(priority = Integer.MAX_VALUE)
public class EntityUtils {

    public static final WrapClass classCraftEntity = ClassUtils.forName("{cb}.entity.CraftEntity");
    public static final WrapClass classNMSEntity = ClassUtils.forName("{nms}.Entity");
    public static final WrapClass classNMSEntityHuman = ClassUtils.forName("{nms}.EntityHuman");

    private WrapField entity;
    private WrapMethod readFromNBT;
    //    private WrapMethod readEntityFromNBT;
    private WrapMethod writeToNBT;
//    private WrapMethod writeEntityToNBT;

    @Inject
    private ItemStackUtils itemStackUtils;
    @Inject
    private MovingObjectPositionUtils movingObjectPositionUtils;
    @Inject
    private NBTCompoundUtils nbtCompoundUtils;

    @PostInstance
    private void init() {
        entity = classCraftEntity.getField("entity");
        writeToNBT = classNMSEntity.getMethod(MethodFilter.build().static_(false).abstract_(false).returnType(void.class, NBTUtils.classNBTTagCompound.getHandle()).parameterType(NBTUtils.classNBTTagCompound.getHandle()).index(0));
        readFromNBT = classNMSEntity.getMethod(MethodFilter.build().static_(false).abstract_(false).returnType(void.class, NBTUtils.classNBTTagCompound.getHandle()).parameterType(NBTUtils.classNBTTagCompound.getHandle()).index(1));
//        readEntityFromNBT = classNMSEntity.getMethod("readEntityFromNBT");
//        writeEntityToNBT = classNMSEntity.getMethod("writeEntityToNBT");
    }

    /**
     * 获取目标方块
     *
     * @param entity
     * @param containsFluid
     * @return
     */
    public Block getTargetBlock(LivingEntity entity, boolean containsFluid) {
        Object movingObjectPosition = itemStackUtils.getMovingObjectPosition(entity, containsFluid);
        if (movingObjectPosition == null) {
            return null;
        }
        return movingObjectPositionUtils.getBlock(entity.getWorld(), movingObjectPosition);
    }

    /**
     * 获取目标方块点击面的相邻方块
     *
     * @param entity
     * @param containsFluid
     * @return
     */
    public Block getTargetBlockNear(LivingEntity entity, boolean containsFluid) {
        Object movingObjectPosition = itemStackUtils.getMovingObjectPosition(entity, containsFluid);
        if (movingObjectPosition == null) {
            return null;
        }
        return movingObjectPositionUtils.getNearBlock(entity.getWorld(), movingObjectPosition);
    }

    public Object toCompound(Object o) {
        Object tag = nbtCompoundUtils.newTagCompound();
        if (o instanceof Entity) {
            o = toNMS((Entity) o);
        }
        writeToNBT.invoke(o, tag);
//        writeEntityToNBT.invoke(o, tag);
        return tag;
    }

    public void fill(Object o, Object nbtTag) {
        if (o instanceof Entity) {
            o = toNMS((Entity) o);
        }
        readFromNBT.invoke(o, nbtTag);
//        readEntityFromNBT.invoke(o, nbtTag);
    }

    public Object toNMS(Entity o) {
        return o == null ? null : entity.get(o);
    }

}
